Skip to content

feat(types): ObjectKanbanSchema.objectName becomes a presence rule on both faces (bind | data | objectName) - #8412

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-7780-object-kanban-record-source
Sep 7, 2026
Merged

feat(types): ObjectKanbanSchema.objectName becomes a presence rule on both faces (bind | data | objectName)#8412
os-zhuang merged 1 commit into
mainfrom
claude/issue-7780-object-kanban-record-source

Conversation

@claude

@claude claude Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Refs #7780

ObjectKanbanSchema.objectName becomes a presence rule on both published faces — at least one of bind, data, objectName — so the declared face matches the record-source ladder ObjectKanban actually walks.

Dispatched by the domain:spec @ objectui PM seat. Clause-②: yes (a published accept set widens), so needs:contract-review is hung on this PR and on the card. ⛔ This PR stays draft and unqueued awaiting that review — that is its sanctioned resting state, not a stall.

The two faces

packages/types/src/objectql.tsobjectName: string becomes objectName?: string, with a docblock naming the four rungs the renderer reads and why this is not the map/gantt/calendar ladder.

packages/types/src/zod/objectql.zod.tsz.string() becomes z.string().optional(), and the member ends in .superRefine(requireKanbanRecordSource). That predicate is new and local, not requireRecordSource:

const KANBAN_RECORD_SOURCE_KEYS = ['bind', 'data', 'objectName'] as const;
function requireKanbanRecordSource(schema, ctx) {
  if (KANBAN_RECORD_SOURCE_KEYS.some((key) => schema[key] !== undefined)) return;
  ctx.addIssue({ code: 'custom', path: [], params: { code: 'RECORD_SOURCE_REQUIRED' },
    message: '`object-kanban` has no record source: declare one of `bind`, `data` or `objectName`' });
}

It is a function, not an export const, for the reason requireRecordSource gives right above it: the parity census reads ^export const out of that directory and would demand a registered TS counterpart.

Also in this PR, as the dispatch requires: the @ts-expect-error in object-calendar-record-source-7313.test.ts that asserted "objectName is still required on ObjectKanbanSchema" is deleted (leaving it would be TS2578 under tsconfig.test.json), and the literal it guarded is renamed and re-documented to record that the class boundary moved.

Accept set, before to after — from source, both entry paths

Measured with a probe against a rebuilt dist, at origin/main fff250ff and at this branch's HEAD deed7878. Every document carries groupBy, so objectName is the one member under test.

document ObjectKanbanSchema.safeParse before after safeValidateSchema before after
bind only REFUSE objectName:invalid_type ACCEPT REFUSE ACCEPT
data only (raw rows) REFUSE objectName:invalid_type ACCEPT REFUSE ACCEPT
objectName only ACCEPT ACCEPT ACCEPT ACCEPT
bind + objectName ACCEPT ACCEPT ACCEPT ACCEPT
data + objectName ACCEPT ACCEPT ACCEPT ACCEPT

Negative controls — refused before, still refused after:

negative control before after
none of the three present REFUSE objectName:invalid_type REFUSE (root):RECORD_SOURCE_REQUIRED
laneless + objectName (no groupBy) REFUSE groupBy REFUSE groupBy
laneless + bind REFUSE objectName + groupBy REFUSE groupBy
laneless + data REFUSE objectName + groupBy REFUSE groupBy
empty node REFUSE objectName + groupBy REFUSE groupBy
retired groupField present REFUSE groupField REFUSE groupField
objectName: 42 REFUSE objectName REFUSE objectName
groupBy: 7 REFUSE groupBy REFUSE groupBy
limit: 0 REFUSE limit:too_small REFUSE limit:too_small
objectName: '' ACCEPT ACCEPT (presence is !== undefined, not truthiness)

No row moved from ACCEPT to REFUSE. Two rows moved REFUSE to ACCEPT, and one refusal moved from a key-level failure to the named refinement at the root path.

One reading worth naming: with groupBy absent the refinement does not fire, because zod 4 skips refinements when the shape parse already failed. That is why the pin's "no record source" document carries groupBy — otherwise the case would go green for the lane key's reasons and stop saying anything about the record source.

groupBy requiredness (PR #7774) is not overturned

PR #7774's groupBy measurement explicitly excluded two readings from counting as a lane-less mode. Both are still refused, and the new pin asserts it:

  • content/docs/utilities/data-objectstack.mdx — the dataSource json fragment. dataSource is not a rung of this ladder (ElementDataSourceGate maps its object onto objectName upstream of the node), so the fragment has no record source and no lane key and is refused for both.
  • packages/plugin-list/src/ListView.tsx — the runtime-generated node, in the shape it emits when the view declared no lane field (groupBy: laneField with laneField undefined). Still refused at groupBy.

The retired groupField tombstone is likewise still refused by name.

objectui#7651 holds — and a reading on its radius

objectui#7651 ("Should ObjectKanban get a real record-source ladder?") was ruled B and closed not_planned on 2026-09-05; its epitaph is in the tree on KanbanSchema.data. It refuses a sixth getDataConfig producer, a ViewData retype of the board's data, and a staticData rung. Nothing here adds a rung, and the pin asserts that by IDENTITY rather than membership — shape.data === BaseSchema.shape.data and shape.bind === BaseSchema.shape.bind — because data and bind reach this member by inheritance through BaseSchema.extend, so membership alone cannot tell inherited from re-declared. A ViewData retype or a staticData addition replaces the entry and reddens it.

⚠️ On its literal radius, the dispatch asked me to measure rather than decide, so this is a reading handed back, not a decision. Measured: #7651's body is written entirely about KanbanSchema.data — the type: 'kanban' interface in packages/types/src/complex.ts — and its epitaph sits on that interface's data member. This card moves ObjectKanbanSchema (type: 'object-kanban', packages/types/src/objectql.ts), a different interface in a different file. So #7651 does not literally cover the member this PR edits. What it does cover, and what this PR obeys, is the substance: it refuses building a record-source ladder for the board, and no rung is built here — the only thing that moved is the requiredness of one member. The refusal list is respected on both interfaces regardless of which one it literally names. ⛔ I did not treat the literal gap as permission for anything; flagged for the contract reviewer.

In-repo census of authored object-kanban nodes

Instrument: every git-tracked file under apps/ · examples/ · content/ · packages/ whose bytes contain object-kanban (93 files), scanned for occurrences where the token is the value of a type key, then walked out to the enclosing brace-balanced literal and read at depth 1. 49 occurrences recognised.

class count notable sites
objectName-only 23 content/docs/plugins/plugin-kanban.mdx (the documented object-driven board)
no rung at all 20 the two PR #7774 exclusions; renderer/registration/i18n string sites
data-only 2 plugin-kanban/src/ObjectKanban.overlayTitleI18n.test.tsx, …overlayTitleNoProviderFallback.test.tsx
data + objectName 2
bind-only 1 packages/types/src/base.ts — the JSON example in BaseSchema.bind's docblock
unparsed 1

Control — the instrument fires. A known-positive bind-only node was planted as a tracked file, the census re-run, and the plant reported by path and line (bind-only 1 to 2); removing it restored output byte-identical to the baseline run, with a clean git status. The positives above are the other half of that control: the walker finds the well-formed nodes too, not only the planted one.

Radius, stated rather than implied. It does not see nodes assembled at runtime by spread or variable, nodes whose type is a variable, or nodes assembled across files — and ⛔ authorship outside this repository is not measurable from this checkout at all: customer apps, published examples and stored page documents are simply not in the walk. No claim is made about them.

⚠️ Honest consequence, and it is not the flattering one. The single authored bind-only node in this repo — the BaseSchema.bind docblock example — also carries no groupBy, so this widening alone does not make it validate; it stays refused, at groupBy. The two data-only fixtures are the nodes this change actually unblocks: both carry an as never escape whose comment names this issue and says "when #7780 lands, this one follows". Those files are in packages/plugin-kanban/**, which this card does not hold, so they are not converted here.

Corrections to the inherited premises — both measured

① The plugin's own KanbanSchema at plugin-kanban/src/types.ts:89 does not exist — CONFIRMED false, as the dispatch stated. wc -l on that file is 59, so :89 cannot exist; grep -rnE '(interface|type|const) +KanbanSchema\b' packages/plugin-kanban/ returns 0 hits (exit 1) while the same pattern over packages/types/src/ fires on complex.ts and zod/complex.zod.ts (exit 0). The KanbanSchema in that file is a pure re-export, collapsed to one source by objectui#7664.

② The props type is a union — CONFIRMED, and this card needs no domain:ui leg. packages/plugin-kanban/src/ObjectKanban.tsx declares schema: KanbanSchema | ObjectKanbanSchema;, not the bare KanbanSchema that triage 5557326104 §4 measured. It already carries both arms, so there is nothing for a ui leg to change. Stronger than that: KanbanSchema.objectName was already optional, so on the union the property already resolved to string | undefined — making ObjectKanbanSchema.objectName optional does not move the union's property type at all. Measured, not inferred: pnpm exec vitest run --maxWorkers=2 packages/plugin-kanban/ is 30 files / 204 tests green on this branch, unchanged.

Parity — measured, not asserted

The dispatch declined to assert whether this widening moves a zod-mirror-parity.test.ts ledger row or an objectui#7279 header figure, and asked for a measurement. It does not, and here is the two-leg evidence rather than a claim:

  • With the change: the parity suite and every objectui#7279 header pin are green in the 142-file packages/types/ run.
  • With the change reverted (the ablation below): the parity suite is still green — it is not named among the failures. So its silence is not a side effect of anything this PR did.

The mechanism: no key is added or removed on either face, so both key sets are unchanged; optionality moved on both faces in the same stroke, so no required-vs-optional drift row is created; and zod 4 attaches .superRefine in place, leaving .shape exposed (measured directly, and the sibling members ObjectMapSchema / ObjectGanttSchema / ObjectCalendarSchema already carry refinements and sit in the same census). ⇒ zod-mirror-parity.test.ts needs no edit, and PR #8354 is not touched.

Reverse verification

Both faces reverted in one mutation, restored by git checkout HEAD -- (paths) under an EXIT INT TERM trap on absolute paths.

  • Mutation reached disk, proven by blob hash, not by an exit code: objectql.ts 5d76024d to f7c01902; objectql.zod.ts 4ddc342c to 03b7ab9b. Anchored counts moved with it: superRefine(requireKanbanRecordSource) 1 to 0, the injected void requireKanbanRecordSource; 1, the optional objectName describe string 1 to 0, objectName?: string; 7 to 6.
  • RED leg: 1 failed | 141 passed (142) files, 7 failed | 2705 passed (2712) tests. The one red file is object-kanban-record-source-7780.test.ts, and only it. All seven red assertions are this card's own subject (the four documents, the published entry point, .shape optionality, the no-rung identity pin, the sibling-ladder contrast). The groupBy-requiredness block and the off-disk renderer-read block stayed green, correctly — the mutation does not touch those facts.
  • Restoration proven by state, not by exit code: both blob hashes equal their HEAD blobs exactly, git diff HEAD is 0 bytes, git status --porcelain empty.
  • GREEN leg: 142 passed (142) files, 2712 passed (2712) tests.

No dist rebuild is needed between legs here, and that is a property of the resolution path rather than an assumption: the pin imports '../zod/objectql.zod', a relative source specifier inside the same package, so no dist/ is in the path — which the red leg demonstrates by going red with no rebuild at all.

Gates (exit codes captured before any pipe)

gate exit verdict line
pnpm exec vitest run --maxWorkers=2 packages/types/ 0 Test Files 142 passed (142) · Tests 2712 passed (2712)
pnpm exec vitest run --maxWorkers=2 packages/plugin-kanban/ 0 Test Files 30 passed (30) · Tests 204 passed (204)
pnpm --filter @object-ui/types build 0 dist completeness: 1 package(s) complete (124 emitted files verified)
pnpm --filter @object-ui/types type-check 0 tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json
node scripts/check-changeset-presence.mjs 0 3 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)
pnpm check:spec-symbols 0 nothing cites a key its spec symbol does not declare
pnpm check:control-bytes 0 OK (scanned 6659 tracked text file(s); skipped 85 binary)
pnpm check:unreferenced-sources 0 Every shipped source file in every covered package is reachable
node scripts/check-governed-queue-guard.mjs --test (5 paths) 0 NOT GOVERNED — 5 path(s) checked against 5 governed surface(s); none matched
pnpm exec eslint . --format json 0 4457 files linted repo-wide, 0 errors; all four changed files present in the run with 0 errors

tsconfig.test.json demonstrably covers the new pin rather than excluding it: tsc -p tsconfig.test.json --listFiles puts it in a 605-file program (the 7313 pin is there as the control).

⚠️ One gate NOT MEASURED locally, declared rather than skipped silently: pnpm check:readme-exports exits 1 in this worktree, and 514 of its 517 findings are literally type entry ./dist/index.d.ts is not on disk -- run pnpm build first; the other three are ratchet floors that read the same unbuilt packages (packagesRead: found 2, floor is 25). It needs a full monorepo build, which CI does. It is unrelated to this diff on the evidence: no README is touched, no export is added or removed from any shipped entry point (the only renamed export const is inside a test file), and zero of its findings name @object-ui/types — the one package that is built here.

验收备注

Out-of-scope observations, recorded rather than filed and not acted on:

None of the three is a reproducible defect, a declared-contract violation, or a trap producing runtime-rejected metadata, so none was filed as a card.

⛔ Not flipped ready, not enqueued, no auto-merge, not self-approved. This session's GitHub identity is os-zhuang, which is both a GOVERNED_APPROVER and this PR's author.


Generated by Claude Code

…th faces

`ObjectKanban` resolves rows through the pre-fetched `data` prop, then `bind`,
then the inline row array on `schema.data`, and only then a fetch keyed by
`schema.objectName` — every `objectName` read guarded. Both published faces
nevertheless REQUIRED `objectName`, so a `bind`-only or `data`-only board that
renders correctly was refused by the shipped validator and could not be
annotated with its own type.

`objectName` is now optional on the interface and on the mirror, with the
requirement the renderer really has expressed as a refinement:
`requireKanbanRecordSource` — at least one of `bind`, `data`, `objectName`.

Deliberately NOT the map / gantt / calendar predicate: that ladder is
`data` (a ViewData provider block) -> `staticData` -> `objectName` through the
shared `resolveRecordSourceConfig`. This board has no `staticData` rung, reads
`data` as a raw row array, has a `bind` rung the other three never walk, and
calls `getDataConfig` zero times. objectui#7651 (ruled B, closed not_planned)
refuses building the shared ladder here; nothing here adds a rung, and `data` /
`bind` stay inherited from `BaseSchema` rather than re-declared.

`groupBy` stays REQUIRED (objectui#7322, PR #7774): a record source and a lane
key are different questions, and the two readings that PR excluded from
counting as a lane-less mode are pinned still-refused.

Refs #7780

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QtGhnU3WnnWyiWeYQhw2aX
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 50 chunks) 3472.6 KB 3512.7 KB
Main entry chunk (gzip) 143.9 KB 350 KB
Entry file index-6MH3gZqY.js
Status PASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 15.67KB 5.75KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 25.05KB 9.16KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.18KB 10.59KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.41KB 1.23KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.46KB 3.43KB
auth (index.js) 3.19KB 1.44KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 5.13KB 2.35KB
collaboration (CommentThread.js) 26.08KB 7.56KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 498.55KB 114.03KB
core (index.js) 7.48KB 2.96KB
create-plugin (index.js) 10.12KB 3.28KB
data-objectstack (index.js) 189.15KB 52.56KB
fields (index.js) 243.15KB 61.40KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 1.22KB 0.64KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 6.57KB 2.76KB
i18n (index.js) 3.65KB 1.47KB
i18n (pickLocalized.js) 7.62KB 3.26KB
i18n (provider.js) 26.89KB 9.04KB
i18n (useDisplayLocale.js) 2.85KB 1.45KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 38.84KB 10.94KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 4.39KB 1.66KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 11.71KB 4.29KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 5.12KB 1.74KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 15.16KB 3.68KB
plugin-calendar (index.js) 49.00KB 13.91KB
plugin-charts (index.js) 71.39KB 19.92KB
plugin-chatbot (index.js) 194.49KB 46.33KB
plugin-dashboard (index.js) 131.48KB 34.45KB
plugin-designer (index.js) 213.21KB 43.63KB
plugin-detail (index.js) 248.68KB 63.94KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 131.01KB 32.32KB
plugin-gantt (index.js) 167.16KB 40.99KB
plugin-grid (index.js) 208.58KB 56.63KB
plugin-kanban (index.js) 55.38KB 15.72KB
plugin-list (index.js) 113.38KB 27.73KB
plugin-map (index.js) 20.49KB 6.83KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.42KB 11.92KB
plugin-timeline (index.js) 30.10KB 8.74KB
plugin-tree (index.js) 9.33KB 3.25KB
plugin-view (index.js) 84.46KB 20.80KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 81.07KB 26.86KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.63KB 2.18KB
react (schema-input.js) 2.32KB 1.24KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 6.58KB 2.74KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 5.55KB 2.45KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (parse.js) 20.57KB 5.88KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 13.64KB 4.59KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 4.73KB 2.28KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Copy link
Copy Markdown
Contributor

PM 落地 — 契约复核 PASS,已翻 ready 并入队

domain:spec @ objectui PM 席。契约复核在档 PASS(卡片 #7780 上的凭证评论 5576500823),双载体 needs:contract-review 已同笔从卡片与本 PR 剥除。

三条落地判据,全部在 ready 那一刻重测 —— ⛔ 不沿用复核时的读数。 这一点不是形式:复核当时我钉的 main 是 9b1b105d,而现在 main 已走到 ca394272,旧的 merge-tree 读数是一棵死树上的读数,本身不入账。

判据 读数 结论
① 席内契约档 PASS 在卡 卡片 #7780 评论 5576500823
check-clause2-carriers --pair 8412 EXIT 0 — 固定拼法可读,双肢一致
③ 全 check 全绿 32 个 check run:29 success · 3 skipped · 0 failure · 0 pending
③ head 与复核所钉 sha deed7878ab0b9f528f9cdf352a9ee5fc765ceefd,逐字一致
③ 对当前 main 无冲突 git merge-tree --write-tree origin/main deed7878EXIT 0,单树 7e9d7d7b

LintType Check 两个 required 地板均 success;入队资格另要求的全部 check 全绿也成立(三个 skipped 分别是 Test (coverage)Test (coverage shard …)dependabot,均为条件跳过,非失败)。

main 漂移的语义面也读了一次,不只读了冲突面。 merge-base fff250ffca394272 之间 main 动了 55 个文件,与本 PR 的 5 个文件交集为空。其中 packages/plugin-list/src/ListView.tsx 值得点名:它是本 PR 正文里 lane-less 反向对照所引用的站点,但钉子 object-kanban-record-source-7780.test.ts 住在 packages/types/src/__tests__/,断言的是它自己内联的文档,不 import plugin-list —— 引用不等于依赖,该漂移不动这条读数。

闭合关键词两读 —— 用 GitHub 自己的解析器读,不是肉眼扫

首行 Refs #7780,卡号旁零动词。全正文的第二读没有靠我自己的正则:正文里出现的每个 open/closed 卡号都回查了它的 closed_by_pull_requests,那是 GitHub 解析器自己的读数。

⇒ 本 PR 的正文关闭不了任何卡,包括它自己那张。这是安全拼法,不是遗漏。

合并后待办(记进落地待办,⛔ 不留给下次巡检)

Refs 收口的卡不会自动关。#7780 的 types 半边由本 PR 全额交付(packages/plugin-kanban/**domain:ui#7664,本卡从不持有),所以合并后:手工关闭 #7780,并手工摘 pm:dispatched

正文里两句现已被本次动作取代

dev 报告写的「⛔ 本 PR 保持 draft 与未入队,等待复核」与「⛔ 未翻 ready、未入队」,是交报那一刻对自身停放状态的如实记述,当时正确。ACCEPT 之后的路径分叉是 PM 的,不是 dev 的 —— 现由本评论记录状态迁移,正文不改写,以免在一份 500 行正文上引入誊抄缺陷。

⛔ 未自审批。本会话的 GitHub 身份 os-zhuang 既是 GOVERNED_APPROVER 又是本 PR 作者,合并交给队列,不由本席落锤。


Generated by Claude Code

Merged via the queue into main with commit 786bc91 Sep 7, 2026
34 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-7780-object-kanban-record-source branch September 7, 2026 23:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants